from typing import Tuple
from flask_restx import abort

from app.common.base_manager import BaseManager
from app.models import userModel
from tools import db


class UserError(Exception):
    pass


class UsersManager(BaseManager):
    """
    用户管理器
    since: 22.2.22
    """

    Model = userModel.User
    Error = UserError

    def add_user(
        self,
        username,
        email,
        role_id,
        password,
        confirm_password,
        **kwargs,
    ):
        """
        添加用户
        """

        if password != confirm_password:
            self.error_func("确认密码和密码不一致!")

        if userModel.User.query.filter_by(username=username).first():
            self.error_func("用户名已存在!")

        if userModel.User.query.filter_by(email=email).first():
            self.error_func("邮箱已被使用!")

        kwargs["username"] = username
        kwargs["email"] = email
        kwargs["password"] = password
        kwargs["role_id"] = role_id

        try:
            with db.auto_commit():
                user = userModel.User(**kwargs)
                userModel.db.session.add(user)
                userModel.db.session.commit()
        except:  # noqa
            self.error_func("参数错误!")

    def update_user(self, user_id, username=None, account_name=None, email=None):
        user = self.get_obj_or_error(id=user_id)

        if username:
            if userModel.User.query.filter(
                userModel.User.username == username, userModel.User.id != user_id
            ).first():
                self.error_func("用户名已存在!")
            user.username = username

        if account_name:
            user.account_name = account_name

        if email:
            if userModel.User.query.filter(
                userModel.User.email == email, userModel.User.id != user_id
            ).first():
                self.error_func("邮箱已被使用!")
            user.email = email

        with db.auto_commit():
            userModel.db.session.commit()

    def delete_user(self, user_id_or_user):

        if isinstance(user_id_or_user, (int, str)):
            user = self.get_obj_or_error(id=user_id_or_user)
        else:
            user = user_id_or_user
        if user.CtfLinkUser:
            for ctf in user.CtfLinkUser:
                if ctf.Ctf is not None:
                    self.error_func("此账号已关联比赛，无法删除!")
        if user.courses.count() >= 1:
            self.error_func("此账号已关联课程，无法删除!")

        if user.is_superuser:
            self.error_func("管理员账户无法删除!")

        if user.groups:
            abort(400, message="此账号已关联红蓝比赛，无法删除")

        userModel.db.session.delete(user)
        userModel.db.session.commit()

    def change_password(self, user_id, password=None, confirm_password=None):
        user = self.get_obj_or_error(id=user_id)
        if not all([password, confirm_password]):
            self.error_func("参数错误!")

        if password != confirm_password:
            self.error_func("确认密码和密码不一致!")

        with db.auto_commit():
            user.password = password
            userModel.db.session.commit()

    @staticmethod
    def get_attr_to_dict(user, attrs=None) -> dict:
        attrs = attrs or []
        r = {}
        for attr in attrs:
            r[attr] = getattr(user, attr, None)
        return r

    def bulk_import(
            self,
            df,
            ignore_errors=False,
    ) -> Tuple:
        """
        批量导入
        :param df: pd.read_excel 返回的对象
        :param ignore_errors: 跳过错误?
        :return 总行数, message
        """
        from app.models.roleModel import PresetRoleChoices, Role

        # 数据库数据 TODO: 查询优化
        user_data = userModel.User.query.with_entities(
            userModel.User.username,
            userModel.User.email,
        ).all()

        user_data = dict(user_data)
        emails = user_data.values()

        project_id = None
        _operator = self.get_operator()
        if _operator:
            project_id = _operator.project_id

        bulk_data = []
        index = 1
        error_index_list = []
        for _, row in df.iterrows():
            index += 1
            if any([
                row.get("*用户名") in user_data,
                row.get("*邮箱") in emails,
            ]):
                if not ignore_errors:
                    self.error_func(f"Excel表格第{index}行用户名或邮箱重复!")
                else:
                    error_index_list.append(index)
                    continue
            bulk_data.append(
                {
                    "username": row.get("*用户名"),
                    "account_name": row.get("*姓名"),
                    "email": row.get("*邮箱"),
                    "password": row.get("*密码"),
                    "role_id": 0,  # 默认身份为 0=学生
                    'project_id': project_id
                }
            )
        # 默认学生权限
        roles = Role.query.filter(
            Role.name == PresetRoleChoices.student.value
        ).all()

        # 批量插入
        with db.auto_commit():
            for item in bulk_data:
                user = userModel.User(
                    **item
                )
                db.session.add(user)
                db.session.flush()
                user.roles = roles

        total = index - 1
        message = f'共{total}条数据, 导入成功{total - len(error_index_list)}条.'
        if error_index_list:
            message += f'其中第{",".join([str(i) for i in error_index_list])}行(用户名或邮箱重复)未能导入!'
        return total, message


users_manager = UsersManager(need_model=True)
